#include "frame.h"
#include "player_bonus.h"
#include "turn.h"
#include "frame_behaviour.h"

#define PINS_COUNT 10

Frame::Frame(std::shared_ptr<FrameBehaviour> frameBehaviour)
    : _scores(0),
      _throwCount(0),
      _pinsLeft(PINS_COUNT),
      _isOpened(true),
      _isDone(false),
      _frameBehaviour(frameBehaviour)
{
}

Frame::Frame()
    : Frame( std::make_shared<FrameBehaviourSimple>() )
{
}

bool Frame::isOpened() const { return _isOpened; }

void Frame::close()
{
	_isOpened = false;
	_scores = PINS_COUNT - _pinsLeft;
}

Frame::~Frame()
{
}

int Frame::getScores() const
{
	//if (_isOpened)
	//{
	//	return PINS_COUNT - _pinsLeft;
	//}
	
	return _scores;
}

void Frame::finish()
{
    _isDone = true;
}

bool Frame::isDone() const
{
    return _isDone;
}

int Frame::getPinsLeft() const
{
    return _pinsLeft;
}

int Frame::getThrowCount() const
{
	return _throwCount;
}

void Frame::addScores(int scores)
{
	_scores += scores;
}

Frame::Bonus Frame::fire(const PinScheme& scheme)//(Turn& turn)
{
    _turns.push_back(scheme.toKnocked(_turns.size() ? _turns.back() : PinScheme()));    
    PinScheme knocked = _turns.back();

    int knockedPinCount = knocked.getMarkedCount();
	assert(knockedPinCount >= 0);
	Bonus turnBonus = Bonus::NONE;
	addScores(knockedPinCount);
	_pinsLeft -= knockedPinCount;
    
	assert(_pinsLeft >= 0);
	
	++_throwCount;
	
	if (knockedPinCount == PINS_COUNT)
	{
		turnBonus = Bonus::STRIKE;
	}
	else if (_pinsLeft == 0)
	{
		turnBonus = Bonus::SPARE;
	}
    
    _frameBehaviour->fired(this, knockedPinCount);
    if (_frameBehaviour->isDone())
    {
        finish();
    }
	
	// add logic for split, i need receive pins scheme for it.
	// ...
	
	if (turnBonus != Bonus::NONE)
	{
		_bonuses.push_back(turnBonus);
		std::unique_ptr<FrameBonus> special = FrameBonusFactory::create(turnBonus, this, knockedPinCount);
		if (special.get() != nullptr)
		{
			_specials.push_back(std::move(special));
		}
        else
        {
            std::cout << "special is null\n";
        }
	}
	
	return turnBonus;
}
void Frame::castSpecials()
{
    for (auto& special : _specials)
    {
        special->cast();
    }
}